﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace SketchUpAPI.NET.Objects
{
    /// <summary>
    /// 4*4 的变换矩阵
    /// </summary>
    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    public struct Transformation
    {
        public double m00;
        public double m10;
        public double m20;
        public double m30;
        public double m01;
        public double m11;
        public double m21;
        public double m31;
        public double m02;
        public double m12;
        public double m22;
        public double m32;
        public double m03;
        public double m13;
        public double m23;
        public double m33;

        /// <summary>
        /// 默认矩阵
        /// </summary>
        public static Transformation Identity
        {
            get
            {
                Transformation t = new Transformation();
                t.m00 = t.m11 = t.m22 = t.m33 = 1;
                return t;
            }
        }

        /// <summary>
        /// [,] operator, indexes by row, column.
        /// </summary>
        /// <param name="r"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        unsafe public double this[int r, int c]
        {
            get
            {
                fixed (double* m = &m00)
                {
                    return m[c * 4 + r];
                }
            }
        }

        /// <summary>
        /// 将变换应用到向量
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public Vector3D ApplyTo(Vector3D source)
        {
            double x = m00 * source.X + m01 * source.Y + m02 * source.Z + m03 * 1;
            double y = m10 * source.X + m11 * source.Y + m12 * source.Z + m13 * 1;
            double z = m20 * source.X + m21 * source.Y + m22 * source.Z + m23 * 1;
            double con = m30 * source.X + m31 * source.Y + m32 * source.Z + m33 * 1;

            x /= con;
            y /= con;
            z /= con;

            return new Vector3D(x, y, z);
        }

        /// <summary>
        /// 将变换应用到点
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public Point3D ApplyTo(Point3D source)
        {
            double x = m00 * source.X + m01 * source.Y + m02 * source.Z + m03 * 1;
            double y = m10 * source.X + m11 * source.Y + m12 * source.Z + m13 * 1;
            double z = m20 * source.X + m21 * source.Y + m22 * source.Z + m23 * 1;
            double con = m20 * source.X + m21 * source.Y + m22 * source.Z + m23 * 1;

            x /= con;
            y /= con;
            z /= con;

            return new Point3D(x, y, z);
        }
    }
}